#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define N 256

void print_arr_one_dimensional(int* a, int n) {
    printf("The one-dimensional array is:");
    for (int i = 0; i < n; i++) {
        printf("%d ", a[i]);
    }
    printf("\n");
}

void print_arr_two_dimensional(int a[][16], int row, int colmn) {
    printf("The two-dimensional array is:\n");
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < colmn; j++) {
            printf("%d ", a[i][j]);
        }
    }
    printf("\n");
}

// 二进制转十进制函数
// 取出前4位和后4位作为二进制
// int ConvertDecimal(int num) {

// }

int main()
{
    int n;
    printf("输入产生随机数个数:\n");
    scanf("%d", &n);
    if (n>255) {
        printf("请输入一个小于等于255的数。\n");
        return -1;
    }
    FILE* p;
    char s[3][7] = {"1.txt", "2.txt", "3.txt"};
    srand(time(NULL)); // 把当前时间作为种子，使得程序每次产生不同的序列
    int tmp = rand() % 3;
    p = fopen(s[tmp], "r");
    // 随机文件已完成
    FILE* f = p;
    int c;
    int a[N] = {0};
    // int i = 0;
    int a_length = n+1;
    for (int i = 0; i < a_length; i++) {
        c = fgetc(f);
        a[i] = c - 48;
    }
    // 文件n+1字节读入到数组了
    // 现在取一个自然排列
    int DTab[N] = {0};
    int DTab_length = n+1;
    for (int i = 0; i < DTab_length; i++) {
        DTab[i] = i;
    }

    // 下面计算j
    int j;
    for (int i = n; i>0; i--) {
        j = (a[i-1]+a[i]) % i;

        DTab[i] ^= DTab[j];
        DTab[j] ^= DTab[i];
        DTab[i] ^= DTab[j];
    }

    print_arr_one_dimensional(DTab, DTab_length);

    int DTabTrue[16][16];
    int k = 0;
    for(int i = 0; i < 16; i++) {
        for (int j = 0; j < 16; j++) {
            DTabTrue[i][j] = DTab[k++];
        }
    }
    // 打印DTabTrue数组
    printf("DTabTrue:\n");
    print_arr_two_dimensional(DTabTrue, 16, 16);
    // 当前b数组里存放的就是0~255的全排列，这就是S盒（256位输入，256位输出）

    // 下面从随机文件中读取256字节数据形成数据区DArea
    // 下面这部分随机文件读取的操作是照搬上面的代码，略作修改得到的
    FILE* p2;
    int tmp2 = rand() % 3;
    p2 = fopen(s[tmp2], "r"); // s数组定义在上一个生成全排列的代码里面
    // 随机文件已完成
    FILE* f2 = p2;
    int d;
    int DArea[N] = {0};
    // int i = 0;
    int DArea_length = n+1;
    for (int i = 0; i < DArea_length; i++) {
        d = fgetc(f2);
        DArea[i] = d - 48;
    }

    print_arr_one_dimensional(DArea, DArea_length);
    // 已完成从随机文件中读取256字节数据形成数据区DArea
    // 下面进行S-盒变换
    // 取出前4位和后4位作为二进制
    int DArea1[N] = {0};
    k = 0;
    for(int i = 0; i < 256; i+=8) {
        for (int j = 0; j < 8; j++) {
            int row = DArea[i]*8+DArea[i+1]*4 + DArea[i+2]*2+DArea[i+3];
            int colomn = DArea[i+4]*8+DArea[i+5]*4 + DArea[i+6]*2+DArea[i+7];
            DArea1[k++] = DTabTrue[row][colomn];
        }
    }

    printf("After S-box convert:\n");
    print_arr_one_dimensional(DArea1, k);
    // 下面准备P置换
    // P置换相较S盒简单
    int DArea2[256] = {0};
    for (int i = 0; i < 256; i++)
    {
        DArea2[i] = DArea1[DTab[i]];
    }
    print_arr_one_dimensional(DArea2, 256);
    fclose(p);
    fclose(p2);
    return 0;
}
